%{
  open Gencode.ClangExec

 let parse_error p = (* Called by the parser function on error *)
  print_endline p;;
  flush stdout

%}

%token <string>   IDENTIFIER
%token <string>   SIDENTIFIER
%token <int>      INTCONSTANT
%token <bool>     BCONSTANT
%token <Gencode.ClangExec.val_tp> TP
%token OPEN_BRACE CLOSE_BRACE LPAREN RPAREN COLON SEMICOLON
%token PROCESS LOCAL SHARED EQ NEQ ASG DISJ
%token IF THEN ELSE FI WHILE DO END WAIT EOF

%start s
%type <(string,string,string,string) Gencode.ClangExec.proc list> s

%%

s:
    program { $1 }
;

/*------------------------------Program----------------------------------------------------------*/
/* sequence of processes */

program: 
    proc_list_opt EOF                         { $1 }
;

proc_list_opt:
                                              { [] }
  | proc_list                                 { $1 }

proc_list:
    process                                   { [$1] }
  | process proc_list_opt                     { $1::$2 }
;

process:
    header OPEN_BRACE statement_list_opt CLOSE_BRACE        { Proc($1, $3) }
;

/*------------------------------Header---------------------------------------------------------*/
/* Process <name> local ( <var> : <type>; <var> : <type>; ... ) shared ()    */

header:
    PROCESS SIDENTIFIER COLON local_defs shared_defs { Phdr ($2,$4,$5) }
;

local_defs:
                                              { [] }
    | LOCAL LPAREN vdecl_list_opt RPAREN      { $3 }
;

shared_defs:
                                              { [] }
    | SHARED LPAREN svdecl_list_opt RPAREN     { $3 }
;

/* Local vars */

vdecl_list_opt :
                                              { [] }
    | vdecl_list                              { $1 }
;

vdecl_list: 
      vardecl                                 { [$1] }
    | vardecl SEMICOLON vdecl_list_opt        { $1::$3 }
;

vardecl:
      IDENTIFIER COLON TP                     { Vdecl($1,$3) }
;

/* Shared vars */

svdecl_list_opt :
                                              { [] }
    | svdecl_list                              { $1 }
;

svdecl_list: 
      svardecl                                 { [$1] }
    | svardecl SEMICOLON svdecl_list_opt        { $1::$3 }
;

svardecl:
      SIDENTIFIER COLON TP                     { Vdecl($1,$3) }
;

/* Statements */

label:
                                              { None }
    | IDENTIFIER COLON                        { Some $1 }

statement_list_opt:
      label                                   { Cnone $1 }
    | statement_list                          { $1 }

statement_list:
      statement                               { $1 }
    | statement SEMICOLON statement_list_opt  { Cseq(None,$1,$3) }

/* Statement */
statement: 
  | OPEN_BRACE statement_list_opt CLOSE_BRACE                               { $2 }
  | label IDENTIFIER ASG expression                                         { Casg($1,$2,$4) }
  | label IF bexpression THEN statement_list_opt ELSE statement_list_opt FI { Cif($1,$3,$5,$7) }
  | label WHILE bexpression DO statement_list_opt END                       { Cwhile($1,$3,$5) }
  | label IDENTIFIER ASG SIDENTIFIER                                        { Cread($1,$2,$4) }
  | label SIDENTIFIER ASG expression                                        { Cwrite($1,$2,$4) }
  | label WAIT wc_list DO statement_list_opt END                            { Cwait($1,$3,$5) }
;

expression: 
    IDENTIFIER                                          { Evar $1 }
  | immvalue                                            { Eimm $1 }
;

wc_list_opt:
                                                        { [] }
  | wc_list                                             { $1 }

wc_list:
    waitcond                                            { [$1] }
  | waitcond DISJ wc_list_opt                           { $1::$3 }

waitcond:
    SIDENTIFIER EQ expression                           { Weq ($1,$3) }
  | SIDENTIFIER NEQ expression                          { Wneq ($1,$3) }

bexpression:
    expression                                          { Bex $1 }
  | expression EQ expression                            { Beq ($1,$3) }
  | expression NEQ expression                           { Bneq ($1,$3) }

immvalue : 
    BCONSTANT                                           { BoolV($1) }
  | INTCONSTANT                                         { NatV(Big_int.big_int_of_int($1)) }
;
